﻿using System;
using System.Collections;
using System.Collections.Generic;
using MySql.Data.MySqlClient;
using System.Configuration;
using System.IO;
using System.Text.RegularExpressions;
using FindIt.DAL;

namespace FindIt.BLL
{
    public class WebPage
    {
        //private static string webPagesFolder = ConfigurationManager.AppSettings["webPagesFolder"];
        public enum StatusType { normal, warned, removed };
        private string _title;
        private string _url;
        private int _size;
        private bool _isRestricted;
        private DateTime _uploadDate;
        private DateTime _lastUpdate;
        private int _pageRank;
        private int _numViews;
        private DateTime _lastViewed;
        private StatusType _status;
        private Dictionary<string,int> _keywords;
        private ArrayList _complaints;
        private string _owner;

        #region Properties
        public string Title
        {
            get { return _title; }
            set { _title = value; }
        }

        public string URL
        {
            get { return _url; }
            set { _url = value; }
        }

        public int Size
        {
            get { return _size; }
            set { _size = value; }
        }

        public bool IsRestricted
        {
            get { return _isRestricted; }
            set { _isRestricted = value; }
        }

        public DateTime UploadDate
        {
            get { return _uploadDate; }
            set { _uploadDate = value; }
        }

        public DateTime LastUpdate
        {
            get { return _lastUpdate; }
            set { _lastUpdate = value; }
        }

        public int PageRank
        {
            get { return _pageRank; }
            set { _pageRank = value; }
        }

        public int NumViews
        {
            get { return _numViews; }
            set { _numViews = value; }
        }

        public DateTime LastViewed
        {
            get { return _lastViewed; }
            set { _lastViewed = value; }
        }

        public StatusType Status
        {
            get { return _status; }
            set { _status = value; }
        }

        public Dictionary<string,int> KeyWords
        {
            get { return _keywords; }
            set { _keywords = value; }
        }

        public ArrayList Complaints
        {
            get { return _complaints; }
            set { _complaints = value; }
        }
        
        public string Owner
        {
            get { return _owner; }
            set { _owner = value; }
        }
#endregion

        #region Constructors
        public WebPage()
        {
        }

        public WebPage(string title, string url, int size, bool isRestricted, DateTime uploadDate, DateTime lastUpdate,
            int pageRank, int numViews, DateTime lastViewed, StatusType status, string owner)
        {
            this._title = title;
            this._url = url;
            this._size = size;
            this._isRestricted = isRestricted;
            this._uploadDate = uploadDate;
            this._lastUpdate = lastUpdate;
            this._pageRank = pageRank;
            this._numViews = numViews;
            this._lastViewed = lastViewed;
            this._status = status;
            this._owner = owner;
        }

        public WebPage(string title, string url, int size, bool isRestricted, DateTime uploadDate, DateTime lastUpdate, 
            int pageRank, int numViews, DateTime lastViewed, StatusType status, string owner, Dictionary<string,int> keywords)
        {
            this._title = title;
            this._url = url;
            this._size = size;
            this._isRestricted = isRestricted;
            this._uploadDate = uploadDate;
            this._lastUpdate = lastUpdate;
            this._pageRank = pageRank;
            this._numViews = numViews;
            this._lastViewed = lastViewed;
            this._status = status;
            this._owner = owner;
            this._keywords = keywords;
        }

        public WebPage(string title, string url, int size, bool isRestricted, DateTime uploadDate, DateTime lastUpdate,
           int pageRank, int numViews, DateTime lastViewed, StatusType status, string owner, Dictionary<string, int> keywords, ArrayList complaints)
        {
            this._title = title;
            this._url = url;
            this._size = size;
            this._isRestricted = isRestricted;
            this._uploadDate = uploadDate;
            this._lastUpdate = lastUpdate;
            this._pageRank = pageRank;
            this._numViews = numViews;
            this._lastViewed = lastViewed;
            this._status = status;
            this._owner = owner;
            this._keywords = keywords;
            this._complaints = complaints;
        }
        #endregion

        public void AddKeyword(string keyword)
        {
        }

        public void SubmitComplaint(string complaint)
        {
        }

        public void ChangePageRank(int rank)
        {
        }

        public static void GenerateLinkMatrix()
        {
        }

        public static ArrayList GetWebPageList()
        {
            ArrayList list = new ArrayList();
            return list;
        }

        public static ArrayList GetPendingComplaints()
        {
            ArrayList list = new ArrayList();
            return list;
        }

        public void AddWebPageToDB()
        {
            WebPageDB db = new WebPageDB();
            db.AddWebPage(this);
            db.AddKeyWords(this._keywords, this._url);
        }

        public static bool GenerateKeywords(string savedPath, ref Dictionary<string, int> systemGeneratedKeywords, Dictionary<string,int> userProvidedKeywords, int maxCount)
        {
            string cleanedHTML = CleanHTML(savedPath);

            string[] words = cleanedHTML.Split(' ', '?', '!', '@', '#', '$', '\"', ',', '\'', ';', ':',
                  '.', '(', ')', '%', '^', '&', '*', '-', '_', '+', '=', '\\', '/', '{', '}', '[', ']');

            string key = ""; // the 'word' itself 
            Dictionary<string, int> keywords = new Dictionary<string, int>();

            // Now loop through the words and add to the catalog
            foreach (string word in words)
            {
                key = word.ToLower();

                if (RestrictedWord.IsStopWord(key))
                {
                    return false;
                }

                if (key != "" && !RestrictedWord.IsNoiseWord(key))
                {
                    PorterStemmer stemmer = new PorterStemmer();
                    stemmer.stemTerm(key).ToLower();

                    if (userProvidedKeywords.ContainsKey(key))
                    {
                    }

                    else if (keywords.ContainsKey(key))
                    {
                        keywords[key]++;
                    }

                    else
                    {
                        keywords.Add(key, 1);
                    }
                }
            }

            string[] keywordArray = new string[keywords.Count];
            string[] temp = new string[keywords.Count];
            keywords.Keys.CopyTo(keywordArray, 0);
            sortByFrequency(keywordArray, temp, 0, keywordArray.Length - 1, keywords);

            for (int i = 0; i < keywordArray.Length && i < maxCount ; i++)
            {
                systemGeneratedKeywords.Add(keywordArray[i], keywords[keywordArray[i]]);
            }

            return true;
         }

        private static string CleanHTML(string savedPath)
        {
            StreamReader fileReader = System.IO.File.OpenText(savedPath);
            string fileContent = fileReader.ReadToEnd();
            fileReader.Close();

            fileContent = StripHtmlTags(fileContent);

            Regex regex = new Regex(@"\s+|\d+");
            string wordsOnly = regex.Replace(fileContent, " "); // compress all whitespace to one space 

            return wordsOnly;
        }

        private static string StripHtmlTags(string html)
        {
            Regex regex = new Regex("<(.|\n)+?>");

            // Replace all tags with a space, otherwise words either side 
            // of a tag might be concatenated 
            string result = regex.Replace(html, " ");

            // Replace all < and > with &lt; and &gt; 
            result = result.Replace("<", "&lt;");
            result = result.Replace(">", "&gt;");

            return result;
        }

        private static void sortByFrequency(string[] words, string[] temp, int left, int right, Dictionary<string, int> keywordCatalog)
        {
            if (right > left)
            {
                int middle = (right + left) / 2;
                sortByFrequency(words, temp, left, middle, keywordCatalog);
                sortByFrequency(words, temp, middle + 1, right, keywordCatalog);
                frequencyMerge(words, temp, left, middle, right, keywordCatalog);
            }
        }

        private static void frequencyMerge(string[] word, string[] temp, int left, int middle, int right, Dictionary<string, int> keywordCatalog)
        {
            int left_end = middle;
            int right_start = middle + 1;
            int cursor = left;
            int count = right - left + 1;

            while ((left <= left_end) && (right_start <= right))
            {
                if (keywordCatalog[word[left]] > keywordCatalog[word[right_start]])
                {
                    temp[cursor] = word[left];
                    cursor += 1;
                    left += 1;
                }

                else
                {
                    temp[cursor] = word[right_start];
                    cursor += 1;
                    right_start += 1;
                }
            }

            while (left <= left_end)
            {
                temp[cursor] = word[left];
                cursor += 1;
                left += 1;
            }

            while (right_start <= right)
            {
                temp[cursor] = word[right_start];
                cursor += 1;
                right_start += 1;
            }

            for (int i = 0; i < count; i++)
            {
                word[right] = temp[right];
                right -= 1;
            }
        }

        public static ArrayList PerformSearch(string[] queryParts)
        {
            WebPageDB db = new WebPageDB();
            MySqlDataReader dr =  db.PerformSearch(queryParts);

            ArrayList list = new ArrayList();

            while (dr.Read())
            {
                WebPage webPage = WebPage.GetWebPageByURL(dr["WebPageURL"].ToString());
                list.Add(webPage);
            }

            return list;
        }

        public static WebPage GetWebPageByURL(string url)
        {
            WebPageDB db = new WebPageDB();
            MySqlDataReader dr = db.GetWebPageByURL(url);

            WebPage webPage = new WebPage();

            while (dr.Read())
            {
                webPage.Title = dr["Title"].ToString();
                webPage.URL = dr["URL"].ToString();
                webPage.Size = int.Parse(dr["Size"].ToString());
                if (dr["IsRestricted"].ToString() == "1")
                    webPage.IsRestricted =true;
                else
                    webPage.IsRestricted = false;
                webPage._uploadDate = DateTime.Parse(dr["UploadDate"].ToString());
                webPage._lastUpdate = DateTime.Parse(dr["LastUpdate"].ToString());
                webPage._pageRank = int.Parse(dr["PageRank"].ToString());
                webPage._numViews = int.Parse(dr["NumViews"].ToString());
                webPage._lastViewed = DateTime.Parse(dr["LastViewed"].ToString());
                webPage._status = (StatusType)Enum.Parse(typeof(StatusType), dr["Status"].ToString());
                webPage._owner = dr["Owner"].ToString();
            }

            return webPage;
        }
    }
}